package com.rayc.mall.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rayc.mall.api.client.AddressClient;
import com.rayc.mall.api.client.CartClient;
import com.rayc.mall.api.client.ItemClient;
import com.rayc.mall.api.client.OrderLogisticClient;
import com.rayc.mall.api.dto.*;
import com.rayc.mall.common.enums.OrderStatus;
import com.rayc.mall.common.exception.BadRequestException;
import com.rayc.mall.common.exception.BizIllegalException;
import com.rayc.mall.common.utils.BeanUtils;
import com.rayc.mall.common.utils.CollUtils;
import com.rayc.mall.common.context.AdminContext;
import com.rayc.mall.common.context.UserContext;
import com.rayc.mall.order.domain.po.Order;
import com.rayc.mall.order.domain.po.OrderDetail;
import com.rayc.mall.order.domain.query.OrderPageQuery;
import com.rayc.mall.order.domain.vo.OrderDetailVO;
import com.rayc.mall.order.domain.vo.OrderVO;
import com.rayc.mall.order.mapper.OrderMapper;
import com.rayc.mall.order.service.IOrderDetailService;
import com.rayc.mall.order.service.IOrderService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: Ray-C
 * @CreateTime: 2025-03-26
 * @Description: 订单service实现
 * @Version: 1.0
 */
@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    private final IOrderDetailService detailService;

    //    private final IItemService itemService;
    private final ItemClient itemClient;

    //    private final AddressMapper addressMapper;
    private final AddressClient addressClient;

    //    private final ICartService cartService;
    private final CartClient cartClient;

    //    private final IOrderLogisticsService orderLogisticsService;
    private final OrderLogisticClient orderLogisticClient;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Order createOrder(OrderFormDTO orderFormDTO) {
        Order order = new Order();
        // 构造购物车里的商品的详情
        List<OrderItemDTO> orderItems = orderFormDTO.getDetails();
        if (orderItems == null || orderItems.isEmpty()) {
            throw new BizIllegalException("购物车为空");
        }
        // 获取商品id和数量的Map
        Map<Long, Integer> itemNumMap = orderItems.stream()
                .collect(Collectors.toMap(OrderItemDTO::getItemId, OrderItemDTO::getNum));
        Set<Long> itemIds = itemNumMap.keySet();
        // 查询购物车里的商品
        //        List<ItemDTO> items = itemService.queryItemByIds(itemIds);
        List<ItemDTO> items = itemClient.queryByIds(itemIds).getData();
        if (items == null || items.size() < itemIds.size()) {
            throw new BadRequestException("商品不存在");
        }
        // 基于商品价格、购买数量计算商品总价：totalFee
        int total = 0;
        for (ItemDTO item : items) {
            total += item.getPrice() * itemNumMap.get(item.getId());
        }
        order.setTotalFee(total);
        // 其它属性
        order.setUserId(UserContext.getUser());
        order.setStatus(OrderStatus.UNPAID);
        order.setAddressId(orderFormDTO.getAddressId());
        LocalDateTime now = LocalDateTime.now();
        order.setCreateTime(now);
        order.setUpdateTime(now);
        // 将Order写入数据库order表中
        save(order);

        // 使用商品详情保存订单中每个商品的详情
        List<OrderDetail> details = buildDetails(order.getId(), items, itemNumMap);
        detailService.saveBatch(details);

        // 清理购物车商品
        //        cartService.removeByItemIds(itemIds);
        cartClient.removeByItemIds(itemIds);

        try {
            // 扣减库存，修改销量
            //            itemService.updateStockAndSold(orderItems);
            itemClient.updateStockAndSold(orderItems);
        } catch (Exception e) {
            throw new BizIllegalException("库存不足！");
        }
        return order;
    }

    public void restoreStockAndSold(Long orderId) {
        // 取消订单时需要恢复该订单的商品库存和销量信息
        // 找到该订单对应的所有订单详情
        List<OrderDetail> details = getOrderDetails(orderId);
        if (CollUtils.isEmpty(details)) {
            return;
        }
        // 把数量改成负数再调用同一个方法即可
        details.forEach(orderDetail -> {
            orderDetail.setNum(-orderDetail.getNum());
        });
        List<OrderItemDTO> orderItems = BeanUtils.copyList(details, OrderItemDTO.class);
        //        itemService.updateStockAndSold(orderItems);
        itemClient.updateStockAndSold(orderItems);
    }

    private List<OrderDetail> getOrderDetails(Long orderId) {
        QueryWrapper<OrderDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OrderDetail::getOrderId, orderId);
        return detailService.list(queryWrapper);
    }

    @Override
    // 该方法会被feign调用，且调用时位于事务中，需要补充事务注解
    @Transactional(rollbackFor = Exception.class)
    public void markOrderPaySuccess(Long orderId) {
        Order order = new Order();
        order.setId(orderId);
        order.setStatus(OrderStatus.UNSHIPPED);
        LocalDateTime now = LocalDateTime.now();
        order.setPayTime(now);
        order.setUpdateTime(now);
        updateById(order);
    }

    @Override
    public Page<Order> search(OrderPageQuery query) {
        return lambdaQuery()
                .eq(query.getId() != null, Order::getId, query.getId())
                .eq(query.getUserId() != null, Order::getUserId, query.getUserId())
                .page(query.toMpPage("update_time", false));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus(Long id, Integer status) {
        Order order = getById(id);
        OrderStatus orderStatus = OrderStatus.of(status);
        // 只能发货/取消订单
        if (!orderStatus.equals(OrderStatus.NOT_CONFIRMED) && !orderStatus.equals(OrderStatus.CANCELED)) {
            throw new BizIllegalException("只能发货/取消订单");
        }
        order.setStatus(orderStatus);
        LocalDateTime now = LocalDateTime.now();
        if (orderStatus.equals(OrderStatus.NOT_CONFIRMED)) {
            // 设置发货时间
            order.setConsignTime(now);
            // 创建发货订单
            //            orderLogisticsService.createLogistics(order);
            orderLogisticClient.createLogistics(BeanUtils.copyBean(order, OrderDTO.class));
        } else {
            // 取消订单的话需要把商品库存加回去，把销量扣回去
            restoreStockAndSold(order.getId());
        }
        order.setUpdateTime(now);
        updateById(order);
    }

    void checkLegal(Order order) {
        if (order == null) {
            throw new BizIllegalException("订单不存在");
        }
        if (!AdminContext.isAdmin() && !UserContext.getUser().equals(order.getUserId())) {
            // 非管理员操作/非自己的订单
            throw new BizIllegalException("非自己的订单");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrder(Long id) {
        // 查询支付单
        Order order = getById(id);
        // 合法性判断
        checkLegal(order);
        // 取消订单
        if (!OrderStatus.UNPAID.equals(order.getStatus())) {
            throw new BizIllegalException("订单已支付，无法取消");
        }
        order.setStatus(OrderStatus.CANCELED);
        order.setUpdateTime(LocalDateTime.now());
        updateById(order);
        // 取消订单的话需要把商品库存加回去，把销量扣回去
        restoreStockAndSold(order.getId());
    }

    @Override
    public void confirmOrder(Long id) {
        // 查询支付单
        Order order = getById(id);
        // 合法性判断
        checkLegal(order);
        if (!OrderStatus.NOT_CONFIRMED.equals(order.getStatus())) {
            // 需要是已发货未确认的状态
            throw new BizIllegalException("订单状态错误");
        }
        // 修改订单状态
        LocalDateTime now = LocalDateTime.now();
        order.setStatus(OrderStatus.CONFIRMED);
        order.setFinishedTime(now);
        order.setUpdateTime(now);
        updateById(order);
    }

    @Override
    public List<OrderVO> queryMyOrders() {
        List<Order> orders = lambdaQuery().eq(Order::getUserId, UserContext.getUser()).list();
        if (CollUtils.isEmpty(orders)) {
            return CollUtils.emptyList();
        }
        return BeanUtils.copyList(orders, OrderVO.class);
    }

    @Override
    public OrderDetailVO getOrderDetail(Long orderId) {
        Order order = getById(orderId);
        checkLegal(order);
        // 获取商品详情
        List<OrderDetail> orderDetails = getOrderDetails(orderId);
        List<OrderItemDTO> orderItems = BeanUtils.copyList(orderDetails, OrderItemDTO.class);
        // 获取地址信息
        Long addressId = order.getAddressId();
        //        AddressDTO address = addressMapper.selectById(addressId);
        AddressDTO address = addressClient.queryById(addressId).getData();
        if (address == null) {
            throw new BizIllegalException("收货地址信息错误");
        }
        // 构造对象
        OrderDetailVO orderDetailVO = new OrderDetailVO();
        orderDetailVO.setDetails(orderItems);
        orderDetailVO.setAddress(BeanUtils.copyBean(address, AddressDTO.class));
        return orderDetailVO;
    }

    private List<OrderDetail> buildDetails(Long orderId, List<ItemDTO> items, Map<Long, Integer> numMap) {
        List<OrderDetail> details = new ArrayList<>(items.size());
        LocalDateTime now = LocalDateTime.now();
        for (ItemDTO item : items) {
            OrderDetail detail = new OrderDetail();
            detail.setName(item.getName());
            detail.setSpec(item.getSpec());
            detail.setPrice(item.getPrice());
            detail.setNum(numMap.get(item.getId()));
            detail.setItemId(item.getId());
            detail.setImage(item.getImage());
            detail.setOrderId(orderId);
            detail.setCreateTime(now);
            detail.setUpdateTime(now);
            details.add(detail);
        }
        return details;
    }

    // feign interface
    @Override
    public List<OrderDTO> queryByUserId(Long userId) {
        List<Order> orders = lambdaQuery().eq(Order::getUserId, userId).list();
        if (CollUtils.isEmpty(orders)) {
            return CollUtils.emptyList();
        }
        return BeanUtils.copyList(orders, OrderDTO.class);
    }
}
